
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;


/**
 *
 * @author Russell
 */
public class RC4 {

    private byte[] plainText;
    private int plainTextLength;
    private byte[] key;
    //private int keyLength;
    //private String keyString;
    private int[] state;
    private byte[] cipherBytes;
    private byte[] plainBytes;
    private boolean encrypt;

    public static int byteToInt(byte[] bytes, int size) {
        int result = 0;
        for (int i = 0; i < size; i++) {
            result = (result << 8) + (int) (bytes[i]&0xFF);
        }
        return result;
    }
    
    public void keySchedAlg() {

        for (int i = 0; i < 256; i++) {
            this.state[i] = i;
        }
        int temp = 0;
        int keyValue = 0;
        int j = 0;
        for (int i = 0; i < 256; i++) {

            keyValue = this.key[i % this.key.length]&0xFF; // looks up ascii value from key (was keyString.length)
            j = (j + this.state[i] + keyValue) % 256;
            temp = this.state[i];   // swap i and j states
            this.state[i] = this.state[j];
            this.state[j] = temp;
        }
    }

    public void pRGA() {

        int i = 0;
        int j = 0;
        int temp = 0;
        int encryptByte = 0;



        for (int k = 0; k < this.plainTextLength; k++) // encrypt plain text bytes
        {
            i = (i + 1) % 256;
            j = (j + this.state[i]) % 256;
            temp = this.state[i];   // swap states
            this.state[i] = this.state[j];
            this.state[j] = temp;
            encryptByte = this.state[(this.state[i] + this.state[j]) % 256];  // this is number to xor stream to encrypt

            if (this.encrypt) {
                this.cipherBytes[k] = (byte)(encryptByte ^ this.plainText[k]);;   
            } else {
                //decrypt portion
                this.plainBytes[k] = (byte)(encryptByte ^ this.plainText[k]);
            }
        }
    }

    public RC4(byte[] plainText, boolean iencrypt, byte[] ikey) throws UnsupportedEncodingException {

        String in = new String(plainText, "UTF8");
        //System.out.println("Input: " + in);
        
        this.encrypt = iencrypt;
        this.plainText = new byte[plainText.length];
        this.plainText = plainText;    // plaintext that was input
        this.plainTextLength = this.plainText.length;   // number of bytes to be encrypted
        this.cipherBytes = new byte[this.plainTextLength];
        this.plainBytes = new byte[this.plainTextLength];

        if (this.encrypt) {
            this.plainBytes = this.plainText;
        } else {
            this.cipherBytes = this.plainText;
        }

        //this.keyString = "rc4keyfadfert5b3";  //40 to 256 bit key, enter whatever or can call from function
        //this.key = keyString.getBytes();
        //this.binaryKey = "";
        this.key = ikey;
        this.state = new int[256];
        //this.keyLength = this.keyString.length() * 8;

        // calcBinaryKey();
        keySchedAlg();
        pRGA();
        
        if(this.encrypt){
             String enc = new String(this.cipherBytes, "UTF8");
             //System.out.println("Using key: " + this.key.toString() + "\nEncrypted cipher is: " + enc);
        }else{
            String dec = new String(this.plainBytes, "UTF8");
             //System.out.println("Decrypted cleartext is: " + dec);
        }
       
       
    }

    /**
     * @return the cipherBytes
     */
    public byte[] getCipherBytes() {
        return cipherBytes;
    }

    /**
     * @return the plainBytes
     */
    public byte[] getPlainBytes() {
        return plainBytes;
    }
}
